//
// Created by guoshunw on 24-2-28.
//

#ifndef CMAKE_HELLO_LOG_HEADER_H
#define CMAKE_HELLO_LOG_HEADER_H

#include <iostream>
#include <sstream>

enum LogLevel {
    DEBUG,
    INFO,
    WARN,
    ERROR,
    FATAL
};

class LogMessage {
public:
    explicit LogMessage(const char *file, int line, LogLevel level = LogLevel::INFO)
        : file_(file), line_(line), level_(level) {}
    LogMessage(const LogMessage &) = delete;
    LogMessage(LogMessage &&) = delete;
    LogMessage &operator=(const LogMessage &) = delete;
    LogMessage &operator=(LogMessage &&) = delete;

    [[nodiscard]] inline std::string prefix(size_t width = 20) const {
        std::stringstream ss;
        std::string file = file_;
        if (file.size() > width) {
            file = "..." + file.substr(file.size() - width - 3);
        }
        ss << "[" << file << ":" << line_ << "]"
           << " - ";
        return ss.str();
    }

    static void flush() {
        std::cout << std::endl;
    }

    ~LogMessage() {
        flush();
    };

#if 0
        template<typename T>
        LogMessage &operator<<(const T &value) {
            if constexpr (std::is_same_v<T, const char *>) {
                str_ += value;
            } else {
                str_ += std::to_string(value);
            }
            return *this;
        }
#endif

    friend std::ostream &operator<<(std::ostream &os, const LogMessage &msg) {
        os << msg.prefix() << msg.str_;
        return os;
    }

private:
    const char *file_;
    int line_;
    std::string str_;
    LogLevel level_;
};


#define LOG(level) std::cout << LogMessage(__FILE__, __LINE__, level)

#define LOGI LOG(LogLevel::INFO)
#define LOGW LOG(LogLevel::WARN)
#define LOGE LOG(LogLevel::ERROR)
#define LOGF LOG(LogLevel::FATAL)

#endif//CMAKE_HELLO_LOG_HEADER_H
